﻿//=====================================================================================================
// LocalizationLibrary
// The Localization Library is a collection of reusable software components that provide 
// support for localization. This library enables you to localize WPF, Silverlight and WP7 applications.
// (http://localizationlibrary.codeplex.com)
//=====================================================================================================
// Author: Nicola Gallo (Website: www.nicola.gallo.name, Email: nicolagmt@hotmail.it) 
//=====================================================================================================

namespace LocalizationLibrary.Tests.Infrastructure
{
    //.Net References
    using System;
    using System.Collections.Generic;
    using System.Collections.ObjectModel;
    using System.Linq;
    using System.Text;
    using System.Threading;

    /// <summary>
    /// Defines a LocalizationLibrary context for testing.
    /// </summary>
    public class LocalizationLibraryContext : IDisposable
    {
        //Fields

        private Collection<Thread> _tests;

        //Constructors

        /// <summary>
        /// Creates a new instance of <see cref="LocalizationLibraryContext"/>.
        /// </summary>
        /// <param name="invalidateOnReset">If true when the <see cref="LocalizationManager"/> is reset the context will be invalid.</param>.
        public LocalizationLibraryContext(bool invalidateOnReset)
        {
            this.InvalidateOnReset = invalidateOnReset;
            if (this.InvalidateOnReset)
            {
                LocalizationManager.OnReset += new EventHandler(LocalizationManager_OnReset);
            }
        }

        //Readonly properties

        /// <summary>
        /// Context's values.
        /// </summary>
        protected readonly Dictionary<String, Object> Values = new Dictionary<string, object>();

        //Properties

        /// <summary>
        /// <param name="invalidateOnReset">If true when the <see cref="LocalizationManager"/> is reset the context will be invalid.</param>.
        /// </summary>
        public bool InvalidateOnReset { get; private set; }

        /// <summary>
        /// List of test in execution.
        /// </summary>
        public Collection<Thread> Tests
        {
            get
            {
                if (this._tests == null)
                {
                    this._tests = new Collection<Thread>();
                }
                return this._tests;
            }
        }

        //Methods

        /// <summary>
        /// Disposing code.
        /// </summary>
        public void Dispose()
        {
            try
            {
                foreach (Thread test in this.Tests)
                {
                    if (test.IsAlive)
                    {
                        test.Abort();
                    }
                }
                this.Tests.Clear();
            }
            catch (Exception) { }
            LocalizationManager.OnReset -= new EventHandler(LocalizationManager_OnReset);
        }

        /// <summary>
        /// Starts the test code.
        /// </summary>
        /// <param name="action">Action that will be invoked when the test begins executing.</param>
        public void Start(Action<LocalizationLibraryContext> action)
        {
            if (action == null)
            {
                throw new ArgumentNullException("action parameter shouldn't be null.");
            }
            ParameterizedThreadStart start = new ParameterizedThreadStart((obj) =>
            {
                action((LocalizationLibraryContext)obj);
            });
            Thread thread = new Thread(start);
            this.Tests.Add(thread);
            thread.Start(this);
        }

        /// <summary>
        /// Called when the <see cref="LocalizationManager"/> is reset.
        /// </summary>
        /// <param name="sender"></param>
        /// <param name="e"></param>
        private void LocalizationManager_OnReset(object sender, EventArgs e)
        {
            foreach (Thread test in this.Tests)
            {
                if (test.IsAlive)
                {
                    test.Abort();
                }
            }
            this.Tests.Clear();
        }

        /// <summary>
        /// Blocks the calling thread until the test terminates.
        /// </summary>
        public void Join()
        {
            foreach (Thread test in this.Tests)
            {
                if (test.IsAlive)
                {
                    test.Join();
                }
            }
        }

        /// <summary>
        /// Blocks the calling thread until the engine's localization terminates.
        /// </summary>
        public void WaitForLocalization()
        {
            while (LocalizationManager.EngineInfo.IsLocalizing)
            {
                Thread.Sleep(100);
            }
        }

        /// <summary>
        /// Sets the specified key and value to the <see cref="LocalizationLibraryContext.Values"/> property.
        /// </summary>
        /// <param name="key">key</param>
        /// <param name="value">value</param>
        public void SetValue(String key, Object value)
        {
            lock (this.Values)
            {
                this.Values[key] = value;
            }
        }

        /// <summary>
        /// Gets the value to the <see cref="LocalizationLibraryContext.Values"/> property for the specified key.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="key">key</param>
        /// <returns></returns>
        public T GetValue<T>(String key)
        {
            T retVal = default(T);
            lock (this.Values)
            {
                if (this.Values.ContainsKey(key))
                {
                    retVal = (T)this.Values[key];
                }
            }
            return retVal;
        }

        /// <summary>
        /// Resets the <see cref="LocalizationManager"/>
        /// </summary>
        /// <param name="localizationModelType">Represents the LocalizationModel type to use</param>
        public void Reset()
        {
            this.Reset(typeof(LocalizationProviderMock));
        }

        /// <summary>
        /// Resets the <see cref="LocalizationManager"/>
        /// </summary>
        /// <param name="localizationModelType">Represents the LocalizationModel type to use</param>
        /// <exception cref="ArgumentException">
        /// Thrown whether <paramref name="localizationModelType"/> parameter is null.
        /// </exception>
        /// <exception cref="ArgumentException">
        /// Thrown whether <paramref name="localizationModelType"/> isn't inherit from <see cref="LocalizationProvider"/> class.
        /// </exception>
        public void Reset(Type localizationModelType)
        {
            if ((localizationModelType == null) || (!(typeof(LocalizationProvider).IsAssignableFrom(localizationModelType))))
            {
                throw new ArgumentException();
            }
            if (!LocalizationManager.IsInitialized)
            {
                LocalizationManager.CurrentLanguage = (Language)"en";
                LocalizationManager.AppLocalizationProviderType = localizationModelType;
                LocalizationManager.Initialize();
                LocalizationManager.Reset();
            }
            else
            {
                LocalizationManager.Reset();
                LocalizationManager.CurrentLanguage = (Language)"en";
                LocalizationManager.AppLocalizationProviderType = localizationModelType;
            }
        }
    }
}
